#include "TileForwardNormalMapInstFX.h"

TileForwardNormalMapInstFX::TileForwardNormalMapInstFX(ID3D11Device* device)
	: AbstractFX(device, L"FX/TileForwardNormalMapInst.fxo")
{
	InitInputLayout(device);
	InitShaderVariablePointers();
}

TileForwardNormalMapInstFX::~TileForwardNormalMapInstFX()
{}

void TileForwardNormalMapInstFX::InitInputLayout(ID3D11Device* device)
{
	const D3D11_INPUT_ELEMENT_DESC inputLayout[] = 
	{
		//Per Vertex
		{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0},
		//Per Instance
		{"WORLD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1},
		{"WORLD", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 16, D3D11_INPUT_PER_INSTANCE_DATA, 1},
		{"WORLD", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 32, D3D11_INPUT_PER_INSTANCE_DATA, 1},
		{"WORLD", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D11_INPUT_PER_INSTANCE_DATA, 1},
	};

	CreateInputLayout(device, inputLayout, 8);
}

void TileForwardNormalMapInstFX::InitShaderVariablePointers()
{
	viewProjVar      = effect->GetVariableByName("viewProj")->AsMatrix();
	texTransformVar  = effect->GetVariableByName("texTransform")->AsMatrix();

	rtWidthVar  = effect->GetVariableByName("rtWidth")->AsScalar();
	rtHeightVar = effect->GetVariableByName("rtHeight")->AsScalar();

	diffuseMapVar = effect->GetVariableByName("diffuseMap")->AsShaderResource();
	normalMapVar  = effect->GetVariableByName("normalMap")->AsShaderResource();

	materialVar        = effect->GetVariableByName("mat");
	eyePosVar          = effect->GetVariableByName("eyePosW")->AsVector();
    direcLightVar	   = effect->GetVariableByName("dLight");
	direcLightCountVar = effect->GetVariableByName("dLightCount")->AsScalar();

	//Tile Forward System
	llbVar   = effect->GetVariableByName("LightListBuffer")->AsShaderResource();
	llibVar  = effect->GetVariableByName("LightListIndexBuffer")->AsShaderResource();
	llsebVar = effect->GetVariableByName("LightListStartEndBuffer")->AsShaderResource();
	
	//Hemispherical lighting
	hemiColDownVar = effect->GetVariableByName("HemiColDown")->AsVector();
	hemiColRangeVar = effect->GetVariableByName("HemiColRange")->AsVector();
	
	//SSAO
	viewVar = effect->GetVariableByName("View")->AsMatrix();
	ssaoMapVar = effect->GetVariableByName("SSAOMap")->AsShaderResource();
	ssaoWorldViewProjTexVar = effect->GetVariableByName("SSAOWorldViewProjTex")->AsMatrix();

	//Environment map
	envMapVar = effect->GetVariableByName("EnvironmentMap")->AsShaderResource();
	
	//Shadow map
	shadowMapVar = effect->GetVariableByName("ShadowMap")->AsShaderResource();
	shadowMapViewVar = effect->GetVariableByName("ShadowMapView")->AsMatrix();
	shadowMapProjVar = effect->GetVariableByName("ShadowMapProj")->AsMatrix();
	shadowMapToTexVar = effect->GetVariableByName("ShadowMapToTex")->AsMatrix();
}

void TileForwardNormalMapInstFX::SetCBufferPerDrawCall(CXMMATRIX& viewProj,
		CXMMATRIX& texTrans, Material& mat, 
		CXMMATRIX& view)
{
	viewProjVar->SetMatrix(reinterpret_cast<const float*>(&viewProj));
	texTransformVar->SetMatrix(reinterpret_cast<const float*>(&texTrans));

	materialVar->SetRawValue(&mat, 0, sizeof(Material));

	viewVar->SetMatrix(reinterpret_cast<const float*>(&view));
}

void TileForwardNormalMapInstFX::SetRTDimensions(unsigned width, unsigned height)
{
	rtWidthVar->SetInt(width);
	rtHeightVar->SetInt(height);
}

void TileForwardNormalMapInstFX::SetShaderResources(ID3D11ShaderResourceView* diffuseMap,
	ID3D11ShaderResourceView* normalMap)
{
	diffuseMapVar->SetResource(diffuseMap);
	normalMapVar->SetResource(normalMap);
}

void TileForwardNormalMapInstFX::SetLightingData(XMFLOAT3& eye, 
	DirectionalLight* dLights, unsigned dLightCount,
	ID3D11ShaderResourceView* lightListIndexBuffer, 
	ID3D11ShaderResourceView* lightListStartEndBuffer)
{
	eyePosVar->SetRawValue(&eye, 0, sizeof(XMFLOAT3));
	
	//Cap Direc Lights to 3.
	if (dLightCount > MAX_DIRECTIONAL_LIGHT_COUNT)
		dLightCount = MAX_DIRECTIONAL_LIGHT_COUNT;
	direcLightVar->SetRawValue(dLights, 0, sizeof(DirectionalLight) * dLightCount);
	direcLightCountVar->SetInt(dLightCount);

	//Update LLIB, LLSEB
	llibVar->SetResource(lightListIndexBuffer);
	llsebVar->SetResource(lightListStartEndBuffer);
}

void TileForwardNormalMapInstFX::SetLightListBuffer(ID3D11ShaderResourceView* lightListBuffer)
{
	llbVar->SetResource(lightListBuffer);
}

void TileForwardNormalMapInstFX::SetHemisphericalData(XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange)
{
	hemiColDownVar->SetRawValue(&hemiColDown, 0, sizeof(XMFLOAT3));
	hemiColRangeVar->SetRawValue(&hemiColRange, 0, sizeof(XMFLOAT3));
}

void TileForwardNormalMapInstFX::SetSSAOData(ID3D11ShaderResourceView* ssaoTex, CXMMATRIX &transform)
{
	ssaoMapVar->SetResource(ssaoTex);
	ssaoWorldViewProjTexVar->SetMatrix(reinterpret_cast<const float*>(&transform));
}

void TileForwardNormalMapInstFX::SetEnvironmentMap(ID3D11ShaderResourceView* envCubeMap)
{
	envMapVar->SetResource(envCubeMap);
}

void TileForwardNormalMapInstFX::SetShadowMap(ID3D11ShaderResourceView* shadowMap)
{
	shadowMapVar->SetResource(shadowMap);
}

void TileForwardNormalMapInstFX::SetShadowMapMatricies(CXMMATRIX &view, CXMMATRIX &proj, CXMMATRIX &toTex)
{
	shadowMapViewVar->SetMatrix(reinterpret_cast<const float*>(&view));
	shadowMapProjVar->SetMatrix(reinterpret_cast<const float*>(&proj));
	shadowMapToTexVar->SetMatrix(reinterpret_cast<const float*>(&toTex));
}